package com.shop.wk.config;

import com.shop.wk.config.custom.CustomTokenEnhancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

	@Autowired
	private RedisConnectionFactory redisConnectionFactory;

	@Autowired
	private BCryptPasswordEncoder passwordEncoder;

	/**
	 * 注入用于支持 password 模式
	 */
	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private WebResponseExceptionTranslator customWebResponseExceptionTranslator;

	@Bean
	public TokenStore tokenStore() {
		// 基于 redis 实现，令牌保存到redis，也可以存到数据库中
		return new RedisTokenStore(redisConnectionFactory);
	}

	// 注入自定义令牌生成
	@Autowired
	public CustomTokenEnhancer customTokenEnhancer;

	@Autowired
	private UserDetailsService userDetailsService;

	@Bean
	@Primary
	public DefaultTokenServices defaultTokenServices() {
		DefaultTokenServices services = new DefaultTokenServices();
		services.setAccessTokenValiditySeconds(60 * 60 * 2);// 设置token xx秒过期
		services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 30);// 设置刷新token的过期时间
		services.setTokenStore(tokenStore());
		return services;
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints
				// 用于支持密码模式
				.authenticationManager(authenticationManager)
				// 指定token存储位置
				.tokenStore(tokenStore());
		// 用于刷新token
		endpoints.userDetailsService(userDetailsService);

		// 自定义token生成规则
		endpoints.tokenEnhancer(customTokenEnhancer);

		// 自定义异常
		endpoints.exceptionTranslator(customWebResponseExceptionTranslator);
	}

	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security
				// 允许客户端访问 /oauth/check_token 检查 token uri=/oauth/check_token?token=6662
				.checkTokenAccess("isAnonymous()")// isAuthenticated() 登录后才能访问 permitAll()
													// 允许所有人 isAnonymous() 可以匿名访问
				// 允许表单认证
				.allowFormAuthenticationForClients();
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		// 配置客户端，一般是读取数据库的，因为可能会变动，这里我们写死放在内存中即可
		clients
				// 使用内存设置
				.inMemory()
				// client_id
				.withClient("client")
				// client_secret
				.secret(passwordEncoder.encode("secret"))
				// 授权类型
				.authorizedGrantTypes("password", "refresh_token")
				// 资源Id
				.resourceIds("backend-resources")
				// 授权范围
				.scopes("backend");
	}

}
